package com.cooper.resource.download;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import android.content.Context;
import android.content.SharedPreferences.Editor;
import android.graphics.Bitmap;
import android.os.Handler;
import android.os.Message;
import android.util.Base64;
import android.util.Log;

import com.cooper.android.comm.BitmapUtils;
import com.cooper.resource.download.DownloadResource.DownloadItem;
import com.cooper.scraper.R;

public class DownloadStatus {

	public static final int FAIL_FOR_PREPARE = 0;
	public static final int FAIL_FOR_DOWNLOADING = 1;
	public static final int FAIL_FOR_CANT_CONTINUE = 2;
	public static final int FAIL_FOR_FILE_NOT_FOUND = 3;
	public static final int FAIL_FRO_NO_SPACE = 4;

	public static final String FAIL_NEED_REANALYZE = "FAIL_BUT_NEED_REANALYZE";

	public static final int STATUS_FINISH = 0;
	public static final int STATUS_FAIL = 1;
	public static final int STATUS_DOWNLOADING = 2;
	public static final int STATUS_WAITING = 3;
	public static final int STATUS_STOP = 4;

	public static final String THUMB_FILE_NAME = "thumb.jpg";

	private Context context;

	public DownloadStatus(Context context, DownloadResource downloadResource,
			DownloadListener listener) {
		super();
		this.context = context.getApplicationContext();
		this.downloadResource = downloadResource;
		this.listener = listener;
		if (downloadResource.isFinish()) {
			status = STATUS_FINISH;
		} else
			status = STATUS_WAITING;
	}

	private int status;

	void threadCreate() {
		status = STATUS_WAITING;
		lastFailTime = null;
	}

	public int getStatus() {
		return status;
	}

	private String failReason;

	public String getFailReason() {
		return failReason;
	}

	private DownloadResource downloadResource;

	private DownloadListener listener;

	public DownloadResource getDownloadResource() {
		return downloadResource;
	}

	private final static int BEING_DOWN_MSG = 1;
	private final static int UPDATE_DOWN_MSG = 2;
	private final static int COMPLETE_DOWN_MSG = 3;
	private final static int FAIL_DOWN_MSG = 4;

	private Handler listenerHandle = new Handler() {

		@Override
		public void handleMessage(Message msg) {
			if (listener != null) {
				switch (msg.what) {
				case BEING_DOWN_MSG:
					listener.onBegin(DownloadStatus.this);
					break;
				case UPDATE_DOWN_MSG:
					listener.onUpdate(DownloadStatus.this);
					break;
				case COMPLETE_DOWN_MSG:
					listener.onComplete(DownloadStatus.this);
					break;
				case FAIL_DOWN_MSG:
					listener.onFail(DownloadStatus.this);
					break;
				}
			}
		}

	};

	private long lastSaveLen = 0;

	private static final int SAVE_LEN = 500000;

	public synchronized void updateDownLen() {
		if ((downloadResource.getDownLen() - lastSaveLen) >= SAVE_LEN) {
			listenerHandle.sendEmptyMessage(UPDATE_DOWN_MSG);
			lastSaveLen = downloadResource.getDownLen();
			saveDownInfo();
		}
	}

	public synchronized void beginDown() {
		status = STATUS_DOWNLOADING;
		failReason = context.getResources().getString(R.string.download_fail);
		listenerHandle.sendEmptyMessage(BEING_DOWN_MSG);
	}

	public synchronized void downPrepared() {
		requestReLocation = false;
	}

	private long lastFailLen = 0;
	private Long lastFailTime = null;
	private static final int FAIL_TIME = 1000 * 60 * 2;
	private boolean requestReLocation = false;

	public boolean isRequestReLocation() {
		return requestReLocation;
	}
	
	public boolean downFail(int reasonId,int type){
		return downFail(context.getResources().getString(reasonId),type);
	}

	public synchronized boolean downFail(String reason,int type) {
		if (type == FAIL_FOR_FILE_NOT_FOUND) {
			requestReLocation = true;
			return true;
		}
		boolean canContinue = (type != FAIL_FOR_CANT_CONTINUE);
		boolean result = false;
		if ((type == FAIL_FOR_PREPARE) || (type == FAIL_FRO_NO_SPACE)) {

			result = true;
		} else {
			if (lastFailTime != null
					&& lastFailLen >= downloadResource.getDownLen()) {
				result = (new Date().getTime() - lastFailTime) > FAIL_TIME;
			} else {
				lastFailTime = new Date().getTime();
				lastFailLen = downloadResource.getDownLen();
			}

			if (!result && !canContinue) {
				if (downloadResource.getDownLen() > 0) {
					result = true;
				}
			}
		}
		if (result) {
			status = STATUS_FAIL;
			failReason = reason;
			listenerHandle.sendEmptyMessage(FAIL_DOWN_MSG);
		}
		requestReLocation = false;
		return result;

	}

	public synchronized void downComplete() {
		if (downloadResource.isFinish()) {
			status = STATUS_FINISH;
			listenerHandle.sendEmptyMessage(COMPLETE_DOWN_MSG);
		} else {
			if (status != STATUS_FAIL) {
				status = STATUS_STOP;
				listenerHandle.sendEmptyMessage(UPDATE_DOWN_MSG);
			}
		}
	}

	public synchronized void saveDownInfo() {
		try {
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			try {
				ObjectOutputStream oos = new ObjectOutputStream(baos);
				try {
					oos.writeObject(downloadResource);
					String saveObj = new String(Base64.encodeToString(
							baos.toByteArray(), Base64.DEFAULT));
					Editor editor = context.getSharedPreferences(
							DownloadManagerService.PREF_NAME,
							Context.MODE_PRIVATE).edit();
					editor.putString(downloadResource.getDownloadingSaveDir()
							.getAbsolutePath(), saveObj);
					editor.commit();
				} finally {
					oos.close();
				}
			} finally {
				baos.close();
			}
		} catch (Exception e) {
			Log.e("DownloadStatus", "save Obj fail", e);
		}
	}

	public Bitmap getThumb(int width, int height) {
		File thumbFile = new File(downloadResource.getDownloadingSaveDir()
				.getAbsolutePath() + "/" + THUMB_FILE_NAME);
		if (thumbFile.exists()) {
			try {
				return BitmapUtils.decodeFile(thumbFile, width, height, false);
			} catch (FileNotFoundException e) {
				Log.e("DownloadStatus", e.getMessage(), e);
				return null;
			}
		} else
			return null;
	}

	public List<DownloadItem> getDownloadItem() {
		List<DownloadItem> result = new ArrayList<DownloadItem>();
		for (DownloadItem downloadItem : downloadResource.getDownloadItems()) {
			if (!downloadItem.isFinish()) {
				result.add(downloadItem);
			}
		}
		return result;
	}

}
